package com.zerlings.gabeisfaker.ui.simulator

import android.media.AudioManager
import android.media.MediaPlayer
import android.media.SoundPool
import android.os.Build
import android.os.Bundle
import android.util.SparseIntArray
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import com.dbflow5.database.SQLiteException
import com.zerlings.gabeisfaker.BR
import com.zerlings.gabeisfaker.MyApplication.Companion.context
import com.zerlings.gabeisfaker.R
import com.zerlings.gabeisfaker.data.model.Gun
import com.zerlings.gabeisfaker.data.model.Stats
import com.zerlings.gabeisfaker.data.model.UniqueItem
import com.zerlings.gabeisfaker.data.repository.ItemRepository
import com.zerlings.gabeisfaker.data.repository.StatsRepository
import com.zerlings.gabeisfaker.ui.BaseViewModel
import com.zerlings.gabeisfaker.ui.MainActivity
import com.zerlings.gabeisfaker.ui.MainViewModel
import com.zerlings.gabeisfaker.util.initGun
import kotlinx.coroutines.Dispatchers
import java.util.*
import kotlin.collections.ArrayList

class SimulatorViewModel(arguments: Bundle, private val handle: SavedStateHandle): BaseViewModel() {

    companion object {
        const val KEY_STATS = "key_stats"
    }

    private val statsRepository = StatsRepository

    private val itemRepository = ItemRepository

    val isLocked = MutableLiveData(false)

    val selectedPosition = MutableLiveData(-1)

    val uniqueItem = MutableLiveData<UniqueItem>(null)

    val stats = MutableLiveData<Stats>()

    val gameSpeed = MutableLiveData(1)

    lateinit var title: String

    lateinit var gunList: ArrayList<Gun>

    var simulatorAdapter: SimulatorAdapter

    var infoAdapter: InfoAdapter

    private lateinit var rareItems: List<String>

    private lateinit var rareSkins: List<String>

    private lateinit var caseImageName: String

    private val soundPool: SoundPool = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        SoundPool.Builder()
                .setMaxStreams(2)
                .build()
    } else {
        SoundPool(2, AudioManager.STREAM_MUSIC, 5)
    }

    private val soundMap = SparseIntArray().apply {
        put(1, soundPool.load(context, R.raw.button, 1))
        put(2, soundPool.load(context, R.raw.display, 1))
    }

    private val player: MediaPlayer = MediaPlayer.create(context, R.raw.open_case)

    private val weaponList: ArrayList<Gun> = ArrayList(42)

    private val convertList = ArrayList<Gun>()

    private val classifiedList = ArrayList<Gun>()

    private val restrictedList = ArrayList<Gun>()

    private val milspecList = ArrayList<Gun>()

    private val industrialList = ArrayList<Gun>()

    private val consumerList = ArrayList<Gun>()

    private var unitPrice = 0f

    /**初始化*/
    init {
        getCaseInfo(arguments)
        initGuns()//初始化各品质武器列表
        initWeaponList(weaponList)//初始化游戏列表
        stats.value = restoreStats()
        simulatorAdapter = SimulatorAdapter(BR.gun, R.layout.skin_item, weaponList)
        infoAdapter = InfoAdapter(BR.gun, R.layout.skin_item, gunList, selectedPosition)
    }

    /**转换StatTrak*/
    fun statTrakTransform() {
        if ("the_cobblestone_collection" != caseImageName) {
            gunList.forEach {
                it.isStatTrak = !it.isStatTrak
            }
        }
    }

    /**还原预览列表*/
    fun resetInfoList() {
        if (gunList[0].isStatTrak) {
            statTrakTransform()
        }
        selectedPosition.value = -1
    }

    /**手动添加物品*/
    fun addItem() {
        gunList[selectedPosition.value!!].takeIf { it.quality < MainActivity.LEVEL_CONVERT }
                ?.let {
                    soundPool.play(soundMap.get(1), 1f, 1f, 5, 0, 1f)
                    UniqueItem(it)
                }?.apply {
                    exterior = ""
                    itemRepository.saveItem(this)
                }
    }

    /**解锁并重置列表*/
    fun unlockScreen() {
        initWeaponList(weaponList)
        isLocked.value = false
    }

    /**保存物品*/
    fun saveItem() {
        itemRepository.saveItem(uniqueItem.value!!)
        unlockScreen()
    }

    /**开始游戏*/
    fun onGameStart() {
        soundPool.play(soundMap.get(1), 1f, 1f, 5, 0, 1f)
        player.start()
        isLocked.value = true//一次开箱结束前锁定侧滑菜单并使标题栏左右按钮失效
        launch({
            setChosenWeapon()
            setUniqueItem()
        },{
            when (it){
                is IndexOutOfBoundsException -> {}
                is NullPointerException -> {}
                is SQLiteException -> {}
                else -> {}
            }
            it.printStackTrace()
        }, Dispatchers.Default)
    }

    /**开箱结束后播放音效及更新数据*/
    fun onGameEnd() {
        player.pause()
        player.seekTo(0)
        soundPool.play(soundMap.get(2), 1f, 1f, 5, 0, 1f)
        stats.value!!.totalCost = String.format("%.2f", stats.value!!.totalCost.toFloat() + unitPrice)
        stats.value!!.obtainedValue = String.format("%.2f", stats.value!!.obtainedValue.toFloat() + uniqueItem.value!!.price.toFloat())
        stats.value = stats.value
    }

    /**退出游戏*/
    fun onGameDestroy() {
        player.stop()
        player.release()
        soundPool.release()
        statsRepository.storeStats(stats.value!!)//暂存统计数据
    }

    /**获取传入箱子信息*/
    private fun getCaseInfo(bundle: Bundle) {
        title = bundle.getString("case_name")!!
        caseImageName = bundle.getString("case_image_name")!!
        rareItems = bundle.getStringArray("rare_item_type")!!.toCollection(ArrayList())
        rareSkins = bundle.getStringArray("rare_skin_type")!!.toCollection(ArrayList())
        unitPrice = ((MainViewModel.priceMap[bundle.getString("market_hash_name")!!]
                ?: "0").toFloat()
                + (MainViewModel.priceMap[bundle.getString("key_hash_name")!!] ?: "0").toFloat())
    }

    /**初始化各类武器列表 */
    private fun initGuns() {
        gunList = initGun(caseImageName)
        gunList.forEach {
            when (it.quality) {
                MainActivity.LEVEL_CONVERT -> convertList.add(it)
                MainActivity.LEVEL_CLASSIFIED -> classifiedList.add(it)
                MainActivity.LEVEL_RESTRICTED -> restrictedList.add(it)
                MainActivity.LEVEL_MILSPEC -> milspecList.add(it)
                MainActivity.LEVEL_INDUSTRIAL -> industrialList.add(it)
                else -> consumerList.add(it)
            }
        }
    }

    /**初始化开箱列表 */
    private fun initWeaponList(arrayList: ArrayList<Gun>) {
        val random = Random()
        arrayList.clear()
        if ("the_cobblestone_collection" != caseImageName) {
            for (i in 0..39) {
                val index = random.nextInt(gunList.size)
                val st = random.nextInt(10)
                val gun = if (st == 0) {
                    Gun().apply {
                        gunName = gunList[index].gunName
                        skinName = gunList[index].skinName
                        skinNameMHN = gunList[index].skinNameMHN
                        imageName = gunList[index].imageName
                        quality = gunList[index].quality
                        minWear = gunList[index].minWear
                        maxWear = gunList[index].maxWear
                        caseName = gunList[index].caseName
                        isStatTrak = true
                    }
                } else {
                    gunList[index]
                }
                arrayList.add(gun)
            }
        } else {
            for (i in 0..39) {
                val index = random.nextInt(gunList.size)
                val gun = gunList[index]
                arrayList.add(gun)
            }
        }
    }

    /**计算得到的最终物品类型并替换列表中的相应位置 */
    private fun setChosenWeapon() {
        val random = Random()
        stats.value!!.totalCount++
        val degree: Int
        if ("the_cobblestone_collection" != caseImageName) {
            degree = random.nextInt(782)
            when (degree) {
                in 0 until 2 -> {
                    //极其稀有的物品
                    stats.value!!.rareCount++
                    val rareWeapon = Gun()
                    rareWeapon.gunName = "*Rare Special Item*"
                    rareWeapon.imageName = "rare_special"
                    rareWeapon.quality = MainActivity.LEVEL_RARE
                    weaponList[36] = rareWeapon
                }
                in 2 until 7 -> {
                    stats.value!!.convertCount++
                    weaponList[36] = convertList[random.nextInt(convertList.size)]
                }
                in 7 until 32 -> {
                    stats.value!!.classifiedCount++
                    weaponList[36] = classifiedList[random.nextInt(classifiedList.size)]
                }
                in 32 until 157 -> {
                    stats.value!!.restrictedCount++
                    weaponList[36] = restrictedList[random.nextInt(restrictedList.size)]
                }
                else -> {
                    stats.value!!.milspecCount++
                    weaponList[36] = milspecList[random.nextInt(milspecList.size)]
                }
            }
            if (random.nextInt(10) == 0 && weaponList[36].quality != MainActivity.LEVEL_RARE) {
                weaponList[36] = Gun().apply {
                    gunName = weaponList[36].gunName
                    skinName = weaponList[36].skinName
                    skinNameMHN = weaponList[36].skinNameMHN
                    imageName = weaponList[36].imageName
                    quality = weaponList[36].quality
                    minWear = weaponList[36].minWear
                    maxWear = weaponList[36].maxWear
                    caseName = weaponList[36].caseName
                    isStatTrak = true
                }
            }
        } else {
            degree = random.nextInt(3906)
            when (degree) {
                in 0 until 1 -> {
                    stats.value!!.convertCount++
                    weaponList[36] = convertList[random.nextInt(convertList.size)]
                }
                in 1 until 6 -> {
                    stats.value!!.classifiedCount++
                    weaponList[36] = classifiedList[random.nextInt(classifiedList.size)]
                }
                in 6 until 31 -> {
                    stats.value!!.restrictedCount++
                    weaponList[36] = restrictedList[random.nextInt(restrictedList.size)]
                }
                in 31 until 156 -> {
                    stats.value!!.milspecCount++
                    weaponList[36] = milspecList[random.nextInt(milspecList.size)]
                }
                in 156 until 781 -> {
                    stats.value!!.industrialCount++
                    weaponList[36] = industrialList[random.nextInt(industrialList.size)]
                }
                else -> {
                    stats.value!!.consumerCount++
                    weaponList[36] = consumerList[random.nextInt(consumerList.size)]
                }
            }
        }
        handle.set(KEY_STATS, stats.value)
    }

    /**根据基本物品类型生成具体的独特物品 */
    private fun setUniqueItem() {
        if (this.weaponList[36].quality == MainActivity.LEVEL_RARE) {
            //判断出手套还是刀，手套不能有计数器
            val random = Random()
            val knifeType = rareItems[random.nextInt(rareItems.size)]
            val skinType = rareSkins[random.nextInt(rareSkins.size)]
            uniqueItem.postValue(
                    if ("glove_case" == caseImageName || "operation_hydra_case" == caseImageName
                            || "clutch_case" == caseImageName) {
                        val glove = itemRepository.getGlove(skinType)
                        UniqueItem(glove!!)
                    } else {
                        val knife = itemRepository.getKnife(skinType, knifeType)
                        UniqueItem(knife!!)
                    }
            )
        } else {
            uniqueItem.postValue(UniqueItem(weaponList[36]))
        }
    }

    private fun restoreStats(): Stats{
        if (!handle.contains(KEY_STATS)){
            handle.set(KEY_STATS, statsRepository.restoreStats())
        }
        return handle.get<Stats>(KEY_STATS)!!
    }
}
